package com.poetize.plus.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.poetize.plus.entity.dao.ChildCommentCount;
import com.poetize.plus.entity.dao.CommentDislikeCountDAO;
import com.poetize.plus.entity.dao.CommentFloorDAO;
import com.poetize.plus.entity.dao.CommentLikeCountDAO;
import com.poetize.plus.entity.dto.CommentDTO;
import com.poetize.plus.entity.dto.page.CommentChildPageDTO;
import com.poetize.plus.entity.dto.page.CommentFloorPageDTO;
import com.poetize.plus.entity.dto.page.CommentPageDTO;
import com.poetize.plus.entity.po.Article;
import com.poetize.plus.entity.po.Comment;
import com.poetize.plus.entity.po.User;
import com.poetize.plus.entity.vo.CommentFloorVO;
import com.poetize.plus.entity.vo.page.CommentPageVO;
import com.poetize.plus.mapper.*;
import com.poetize.plus.service.CommentService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author zuosy
 * @created 2024/4/3 14:10
 */
@Service
@RequiredArgsConstructor
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    private final UserMapper userMapper;

    private final ArticleMapper articleMapper;

    private final CommentLikeMapper commentLikeMapper;

    private final CommentDislikeMapper commentDislikeMapper;

    @Override
    public Page<CommentPageVO> commentPage(CommentPageDTO commentPageDTO) {
        Page<Comment> commentPage = lambdaQuery()
                .eq(Objects.nonNull(commentPageDTO.getArticleId()), Comment::getArticleId, commentPageDTO.getArticleId())
                .like(StringUtils.hasText(commentPageDTO.getCreateBy()), Comment::getCreateBy, commentPageDTO.getCreateBy())
                .page(Page.of(commentPageDTO.getCurrent(), commentPageDTO.getSize()));

        Page<CommentPageVO> result = new Page<>();
        List<Comment> comments = commentPage.getRecords();
        if (CollectionUtils.isEmpty(comments)){
            return result;
        }

        //查询文章信息
        List<Long> articleIds = comments.stream().map(Comment::getArticleId).distinct().toList();
        List<Article> articleList = articleMapper.selectBatchIds(articleIds);

        //查询点赞数，点踩数
        List<Long> commentIds = comments.stream().map(Comment::getId).toList();
        List<CommentLikeCountDAO> likeCountDAO = commentLikeMapper.selectCountGroupByCommentId(commentIds);
        List<CommentDislikeCountDAO> dislikeCountDAO = commentDislikeMapper.selectCountGroupByCommentId(commentIds);

        List<CommentPageVO> voList = new ArrayList<>();
        comments.forEach(comment -> {
            Optional<Article> first = articleList.stream().filter(f -> f.getId().equals(comment.getArticleId())).findFirst();
            Optional<CommentLikeCountDAO> likeCountDAOOptional = likeCountDAO.stream().filter(f -> f.id().equals(comment.getId())).findFirst();
            Optional<CommentDislikeCountDAO> dislikeCountDAOOptional = dislikeCountDAO.stream().filter(f -> f.id().equals(comment.getId())).findFirst();

            var articleTitle = "";
            if (first.isPresent()){
                articleTitle = first.get().getArticleTitle();
            }

            var likeCount = 0L;
            var disLikeCount = 0L;
            if (likeCountDAOOptional.isPresent()){
                likeCount = likeCountDAOOptional.get().likeCount();
            }
            if (dislikeCountDAOOptional.isPresent()){
                disLikeCount = dislikeCountDAOOptional.get().dislikeCount();
            }

            CommentPageVO vo = new CommentPageVO(
                    comment.getId(),
                    articleTitle,
                    comment.getCreateBy(),
                    likeCount,
                    disLikeCount,
                    comment.getCommentContent(),
                    comment.getCreateTime()
            );
            voList.add(vo);
        });

        result.setTotal(commentPage.getTotal());
        result.setRecords(voList);
        return result;
    }

    @Override
    public Boolean deleteComment(Long id) {
        return baseMapper.deleteById(id) > 0;
    }

    @Override
    public Integer getMaxFloor(Long articleId) {
        return baseMapper.selectMaxFloorNum(articleId);
    }

    @Override
    public List<CommentFloorVO> getCommentByArticleId(CommentFloorPageDTO commentFloorPageDTO) {
        //计算分页偏移量
        long startOffset = (commentFloorPageDTO.getCurrent() - 1) * commentFloorPageDTO.getSize();
        List<CommentFloorDAO> parentCommentList = baseMapper.selectParentComment(commentFloorPageDTO.getArticleId(), startOffset, commentFloorPageDTO.getSize());
        if (CollectionUtils.isEmpty(parentCommentList)){
            return new ArrayList<>();
        }

        //所有楼层
        List<Integer> floors = parentCommentList.stream().map(CommentFloorDAO::floorNum).toList();

        //子评论个数
        List<ChildCommentCount> commentCount = baseMapper.selectChildCommentCount(commentFloorPageDTO.getArticleId(), floors);

        //评论人信息
        List<String> usernames = parentCommentList.stream().map(CommentFloorDAO::createBy).distinct().toList();
        List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getUsername, usernames));

        List<CommentFloorVO> result = new ArrayList<>();
        parentCommentList.forEach(parentComment -> {
            Optional<User> userOptional = users.stream().filter(f -> f.getUsername().equals(parentComment.createBy())).findFirst();
            if (userOptional.isPresent()){
                //子评论集合     默认展示五条      并按点赞数排序
                List<CommentFloorDAO> childCommentList = baseMapper.selectChildComment(commentFloorPageDTO.getArticleId(), parentComment.floorNum(), 0L, 5L);

                List<CommentFloorVO.CommentFloorChild> child = getChild(parentComment, childCommentList, users);
                User user = userOptional.get();

                Long childCount = 0L;
                Optional<ChildCommentCount> countOptional = commentCount.stream().filter(f -> f.floorNum().equals(parentComment.floorNum())).findFirst();
                if (countOptional.isPresent()){
                    childCount = countOptional.get().count();
                }

                CommentFloorVO vo = CommentFloorVO.convertDAO(parentComment, child, user, childCount);
                result.add(vo);
            }
        });
        //父评论按点赞数量排序
        return result.stream().sorted(Comparator.comparingLong(CommentFloorVO::likeCount).reversed()).toList();
    }

    @Override
    public List<CommentFloorVO.CommentFloorChild> getChildComment(CommentChildPageDTO commentChildPageDTO) {
        List<Comment> commentList = lambdaQuery()
                .eq(Comment::getFloorNum, commentChildPageDTO.getFloorNum())
                .list();
        if (CollectionUtils.isEmpty(commentList)){
            return new ArrayList<>();
        }

        //楼主评论
        CommentFloorDAO commentFloorDAO = baseMapper.selectParentCommentByFloor(commentChildPageDTO.getArticleId(), commentChildPageDTO.getFloorNum());

        //计算子评论分页偏移量
        long startOffset = (commentChildPageDTO.getCurrent() - 1) * commentChildPageDTO.getSize();
        List<CommentFloorDAO> childComment = baseMapper.selectChildComment(commentChildPageDTO.getArticleId(), commentChildPageDTO.getFloorNum(), startOffset, commentChildPageDTO.getSize());

        //评论人信息
        List<String> usernames = childComment.stream().map(CommentFloorDAO::createBy).distinct().toList();
        List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getUsername, usernames));

        return getChild(commentFloorDAO, childComment, users);
    }

    /**
     * 组装楼层
     * @param parentComment
     * @param childCommentList
     * @param users
     * @return
     */
    private List<CommentFloorVO.CommentFloorChild> getChild(CommentFloorDAO parentComment, List<CommentFloorDAO> childCommentList, List<User> users){
        List<CommentFloorVO.CommentFloorChild> childList = new ArrayList<>();
        childCommentList.forEach(child -> {
            Optional<User> userOptional = users.stream().filter(f -> f.getUsername().equals(child.createBy())).findFirst();
            if (userOptional.isPresent()){
                CommentFloorVO.CommentFloorChild floorChild = null;
                User user = userOptional.get();
                //如果是直接回复的楼主，则不加回复人名称;如果在楼层中回复的其他人，则添加回复人名称
                boolean flag = child.parentId().equals(parentComment.id());
                if (flag){
                    floorChild = CommentFloorVO.CommentFloorChild.convertChild(child, user,"");
                }else {
                    Optional<CommentFloorDAO> brother = childCommentList.stream().filter(f -> f.id().equals(child.parentId())).findFirst();
                    if (brother.isPresent()){
                        CommentFloorDAO dao = brother.get();
                        floorChild = CommentFloorVO.CommentFloorChild.convertChild(child, user,dao.createBy());
                    }else {
                        Comment comment = baseMapper.selectById(child.parentId());
                        floorChild = CommentFloorVO.CommentFloorChild.convertChild(child, user, comment.getCreateBy());
                    }
                }
                childList.add(floorChild);
            }
        });
        return childList;
    }

    @Override
    public Boolean publish(CommentDTO commentDTO) {
        Article article = articleMapper.selectById(commentDTO.articleId());
        if (!article.getCommentStatus()){
            throw new IllegalArgumentException("该文章未开启评论");
        }
        int floorNum;
        if (commentDTO.parentId() == 0L){
            Integer maxFloorNum = baseMapper.selectMaxFloorNum(commentDTO.articleId());
            floorNum = maxFloorNum + 1;
        }else {
            Comment comment = baseMapper.selectById(commentDTO.parentId());
            floorNum = comment.getFloorNum();
        }
        Comment comment = CommentDTO.convertDTO(commentDTO, floorNum);
        return baseMapper.insert(comment) > 0;
    }
}
